package com.xy.biz.fd.controller;

import com.xy.biz.fd.domain.bo.DocumentBO;
import com.xy.biz.fd.domain.po.DocumentPO;
import com.xy.biz.fd.manager.DocumentManager;
import com.xy.biz.fd.manager.impl.MinioDocumentManager;
import com.xy.biz.fd.service.impl.DocumentEventBus;
import com.xy.tool.context.UserContextHolder;
import com.xy.tool.minio.util.FileUtility;
import com.xy.tool.minio.util.MinioUtil;
import lombok.extern.slf4j.Slf4j;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.*;
import java.util.Scanner;

/**
 * @Author wwj
 * @Date 2021/1/30
 */
@Slf4j
@Controller
@RequestMapping("/only")
public class CallbackController {

    @Value("${files.docservice.secret}")
    private String secret;

    @Autowired
    private MinioDocumentManager documentManager;

    @Autowired
    private DocumentManager dbDocumentManager;

    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private FileUtility fileUtility;

    @Autowired
    private DocumentEventBus documentEventBus;

    @RequestMapping(value = "/index")
    public void processIndex(HttpServletRequest request, HttpServletResponse response) {

        response.setCharacterEncoding("UTF-8");

        String action = request.getParameter("type");

        if (action == null) {
            try {
                request.getRequestDispatcher("index.jsp").forward(request, response);
            } catch (ServletException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }

        PrintWriter writer = null;
        try {
            writer = response.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }

        switch (action.toLowerCase()) {
            case "upload":
                Upload(request, response, writer);
                break;
            case "convert":
//                Convert(request, response, writer);
                break;
            case "track":
                Track(request, response, writer);
                break;
            case "remove":
//                Remove(request, response, writer);
                break;
        }
    }

    private void Track(HttpServletRequest request, HttpServletResponse response, PrintWriter writer) {
        String userAddress = request.getParameter("userAddress");
        String fileName = request.getParameter("fileName");

        String minioStoragePath = fileName;
        String body = "";

        try {
            Scanner scanner = new Scanner(request.getInputStream());
            scanner.useDelimiter("\\A");
            body = scanner.hasNext() ? scanner.next() : "";
            scanner.close();
        } catch (Exception ex) {
            writer.write("get request.getInputStream error:" + ex.getMessage());
            return;
        }

        if (body.isEmpty()) {
            writer.write("empty request.getInputStream");
            return;
        }

        JSONParser parser = new JSONParser();
        JSONObject jsonObj;

        try {
            Object obj = parser.parse(body);
            jsonObj = (JSONObject) obj;
        } catch (Exception ex) {
            writer.write("JSONParser.parse error:" + ex.getMessage());
            return;
        }

        int status;
        String downloadUri;
        String changesUri;
        String key;

        if (tokenEnabled(secret)) {
//            String token = (String) jsonObj.get("token");
//
//            if (token == null) {
//                String header = (String) request.getHeader(DocumentJwtHeader == null || DocumentJwtHeader.isEmpty() ? "Authorization" : DocumentJwtHeader);
//                if (header != null && !header.isEmpty()) {
//                    token = header.startsWith("Bearer ") ? header.substring(7) : header;
//                }
//            }
//
//            if (token == null || token.isEmpty()) {
//                writer.write("{\"error\":1,\"message\":\"JWT expected\"}");
//                return;
//            }
//
//            JWT jwt = DocumentManager.ReadToken(token);
//            if (jwt == null)
//            {
//                writer.write("{\"error\":1,\"message\":\"JWT validation failed\"}");
//                return;
//            }
//
//            if (jwt.getObject("payload") != null) {
//                try {
//                    @SuppressWarnings("unchecked") LinkedHashMap<String, Object> payload =
//                            (LinkedHashMap<String, Object>)jwt.getObject("payload");
//
//                    jwt.claims = payload;
//                }
//                catch (Exception ex) {
//                    writer.write("{\"error\":1,\"message\":\"Wrong payload\"}");
//                    return;
//                }
//            }
//
//            status = jwt.getInteger("status");
//            downloadUri = jwt.getString("url");
//            changesUri = jwt.getString("changesurl");
//            key = jwt.getString("key");
            /**
             * 支持token后下面的四行要被上面的四行替代，这里复制过来只是为了不报编译错误
             */
            status = Math.toIntExact((long) jsonObj.get("status"));
            downloadUri = (String) jsonObj.get("url");
            changesUri = (String) jsonObj.get("changesurl");
            key = (String) jsonObj.get("key");
        } else {
            status = Math.toIntExact((long) jsonObj.get("status"));
            downloadUri = (String) jsonObj.get("url");
            changesUri = (String) jsonObj.get("changesurl");
            key = (String) jsonObj.get("key");
        }


        int saved = 0;
        //MustSave, Corrupted
        if (status == 2 || status == 3) {
            try {
                String histDir = historyDir(minioStoragePath);
                String versionDir = documentManager.VersionDir(histDir, documentManager.getMinioFileVersion(histDir) + 1);

                //将文件移动到本次历史版本文件夹中，更名为prev.xxx
                //下载+上传
                minioUtil.uploadFile(
                        minioUtil.getObject(MinioUtil.storageBucket, minioStoragePath),
                        versionDir + "/" + "prev" + fileUtility.getFileExtension(fileName),
                        MinioUtil.storageBucket);
                //删除原路径文件
                minioUtil.removeObject(MinioUtil.storageBucket, minioStoragePath);

                //把最新版本下载并上传至原minio路径
                Long size = documentManager.passToMinioFile(downloadUri, minioStoragePath);
                //把变更文件下载并上传至相应的历史版本目录
                documentManager.passToMinioFile(changesUri, versionDir + "/" + "diff.zip");

                String history = (String) jsonObj.get("changeshistory");
                if (history == null && jsonObj.containsKey("history")) {
                    history = ((JSONObject) jsonObj.get("history")).toJSONString();
                }

                //上传changes.json至minio
                if (history != null && !history.isEmpty()) {
                    minioUtil.uploadFile(
                            new ByteArrayInputStream(history.getBytes("UTF-8")),
                            versionDir + "/" + "changes.json",
                            MinioUtil.storageBucket);
                }

                //上传key.txt至minio
                minioUtil.uploadFile(
                        new ByteArrayInputStream(key.getBytes("UTF-8")),
                        versionDir + "/" + "key.txt",
                        MinioUtil.storageBucket);


                DocumentPO documentPO = dbDocumentManager.updateDocumentSizeByPath(DocumentBO.builder().path(minioStoragePath).fileSize(size).build());
                documentEventBus.fireDocumentEditHandler(documentPO.getDocumentId());
            } catch (Exception ex) {
                saved = 1;
            }
        }

        writer.write("{\"error\":" + saved + "}");
    }

    private void Upload(HttpServletRequest request, HttpServletResponse response, PrintWriter writer) {
        response.setContentType("text/plain");

        try {
            Part httpPostedFile = request.getPart("file");

            String fileName = "";
            for (String content : httpPostedFile.getHeader("content-disposition").split(";")) {
                if (content.trim().startsWith("filename")) {
                    fileName = content.substring(content.indexOf('=') + 1).trim().replace("\"", "");
                }
            }

            long curSize = httpPostedFile.getSize();
            if (documentManager.getMaxFileSize() < curSize || curSize <= 0) {
                writer.write("{ \"error\": \"File size is incorrect\"}");
                return;
            }

            String curExt = fileUtility.getFileExtension(fileName);
            if (!documentManager.getFileExts().contains(curExt)) {
                writer.write("{ \"error\": \"File type is not supported\"}");
                return;
            }

            InputStream fileStream = httpPostedFile.getInputStream();

            //todo 文档名称
            fileName = documentManager.getCorrectName(fileName);
            String minFileName = documentManager.getMinCorrectName(fileName);
            minioUtil.uploadFile(fileStream, minFileName, MinioUtil.storageBucket);

            documentManager.createMinioMeta(fileName, UserContextHolder.getUserId() + "",
                    UserContextHolder.getUserName());

            writer.write("{ \"filename\": \"" + fileName + "\"}");

        } catch (Exception e) {
            writer.write("{ \"error\": \"" + e.getMessage() + "\"}");
        }
    }

    private String historyDir(String minioStoragePath) {
        return minioStoragePath += "-hist";
    }

    private boolean tokenEnabled(String secret) {
        return secret != null && !secret.isEmpty();
    }
}
